type AsyncTask = () => Promise<unknown>;

/**
 * 一个带并发控制的异步任务执行器。
 * - 提供 start、stop、push 方法
 * - 列表中存在任务时并发执行，最大并发数默认 5
 * - 任务完成后自动从列表取下一个
 * - 当没有待执行任务且无运行中任务时自动停止
 * - stop 仅停止调度并清空待执行队列，已在执行中的任务不会被中断
 */
class AsyncTaskPool {
  private readonly maxConcurrency: number;
  private readonly queue: AsyncTask[] = [];
  private runningCount: number = 0;
  private running: boolean = false;
  private successCallback = () => {}

  constructor(maxConcurrency: number = 5, successCallback?: () => void) {
    this.maxConcurrency = Math.max(1, maxConcurrency);
    if(successCallback) {
      this.successCallback = successCallback;
    }
  }

  /** 启动调度（幂等） */
  start(): void {
    if (this.running) return;
    this.running = true;
    this.schedule();
  }

  /**
   * 停止调度并清空待执行队列。
   * 注意：已在执行中的任务不会被取消（JS 无法强制中断 Promise）。
   */
  stop(): void {
    this.running = false;
    this.queue.length = 0;
  }

  /**
   * 推入一个或多个异步任务；若当前已停止则自动启动
   */
  push(task: AsyncTask | AsyncTask[]): void {
    const tasks = Array.isArray(task) ? task : [task];
    for (const t of tasks) {
      if (typeof t === 'function') {
        this.queue.push(t);
      }
    }
    if (!this.running) {
      this.start();
      return;
    }
    this.schedule();
  }

  /** 当前是否在运行（有调度或有执行中的任务） */
  isRunning(): boolean {
    return this.running || this.runningCount > 0;
  }

  /** 待执行任务长度 */
  pendingSize(): number {
    return this.queue.length;
  }

  /** 正在执行中的任务数量 */
  activeSize(): number {
    return this.runningCount;
  }

  private schedule(): void {
    if (!this.running) return;
    while (this.running && this.runningCount < this.maxConcurrency && this.queue.length > 0) {
      const next = this.queue.shift();
      if (!next) break;
      this.runTask(next);
    }

    // 无任务且无活动执行时，自动停止
    if (this.running && this.queue.length === 0 && this.runningCount === 0) {
      this.running = false;
      if(this.successCallback) {
        this.successCallback();
      }
    }
  }

  private runTask(task: AsyncTask): void {
    this.runningCount += 1;
    Promise.resolve()
      .then(task)
      .catch(() => {
        // 任务内部错误吞掉以保证池子继续运行；如需上报可在这里统一处理
      })
      .finally(() => {
        this.runningCount -= 1;
        // 若仍在运行或有遗留任务，继续调度
        if (this.running) {
          this.schedule();
        } else if (this.queue.length > 0) {
          // 若被外部 stop 后又有 push 进来但未显式 start，这里不自动拉起
          // 由 push 保证在停止状态下自动 start
        }
      });
  }
}

export default AsyncTaskPool;


